package com.shop.cloud.upms.admin.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.odiszapc.nginxparser.NgxBlock;
import com.github.odiszapc.nginxparser.NgxConfig;
import com.github.odiszapc.nginxparser.NgxEntry;
import com.github.odiszapc.nginxparser.NgxParam;
import com.shop.cloud.common.core.config.HomeDirConfigProperties;
import com.shop.cloud.common.core.util.FileUtils;
import com.shop.cloud.upms.admin.properties.H5portalPathProperties;
import com.shop.cloud.upms.admin.properties.NginxConfigProperties;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.log.annotation.SysLog;
import com.shop.cloud.common.security.annotation.Inside;
import com.shop.cloud.upms.common.entity.H5PortalDomain;
import com.shop.cloud.upms.admin.service.H5PortalDomainService;
import com.shop.cloud.upms.common.entity.WebHost;
import com.shop.cloud.upms.common.util.NginxConfigUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * H5前端域名
 *
 * @author
 * @date 2022-12-14 11:03:21
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/h5portaldomain")
@Tag(description = "h5portaldomain", name = "H5前端域名管理")
public class H5PortalDomainController {

    private final H5PortalDomainService h5PortalDomainService;
    private final NginxConfigProperties nginxConfigProperties;
    private final HomeDirConfigProperties homeDirConfigProperties;
    private final H5portalPathProperties h5portalPathProperties;

    /**
     * H5前端域名分页列表
     * @param page 分页对象
     * @param h5PortalDomain H5前端域名
     * @return
     */
    @Operation(summary = "H5前端域名分页列表")
    @GetMapping("/page")
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:index','mall:shopinfo:index','wxmp:wxapp:index')")
    public R getPage(Page page, H5PortalDomain h5PortalDomain) throws IOException {
        h5PortalDomain.setTenantId(TenantContextHolder.getTenantId());
        IPage iPage = h5PortalDomainService.page(page, Wrappers.query(h5PortalDomain));

        String dirPath = nginxConfigProperties.getConfDir() + h5PortalDomain.getTenantId() + ".conf";
        // 判断当前租户的nginx配置文件是否存在，否则创建
        if (!FileUtil.exist(dirPath)) {
            // 创建配置文件
            FileUtil.touch(dirPath);
        }
        if(iPage.getSize() > 0){
            // 工具：https://github.com/odiszapc/nginx-java-parser    https://blog.51cto.com/u_12995/6342908
            NgxConfig conf = NgxConfig.read(dirPath);
            List<NgxEntry> rtmpServers = conf.findAll(NgxConfig.BLOCK, "server");

            List<H5PortalDomain> listH5PortalDomain = iPage.getRecords();
            listH5PortalDomain.forEach(obj -> {
                String id = obj.getId();
                id = id+ " www." + id;
                Boolean isAccessHttp = false;
                Boolean isAccessHttps = false;
                Boolean isAutoHttps = false;
                Boolean havSslCert = false;
                Boolean havSslCertKey = false;
                for (NgxEntry ngxEntry : rtmpServers) {
                    NgxBlock ngxBlock = (NgxBlock) ngxEntry;
                    String listen = ngxBlock.findParam("listen").getValue();
                    String server_name = ngxBlock.findParam("server_name").getValue();
                    if(server_name.equals(id)){
                        if("80".equals(listen)){
                            isAccessHttp = true;
                            NgxParam return301 = ngxBlock.findParam("return");
                            if(return301 != null){
                                isAutoHttps = true;
                            }
                        }
                        if("443 ssl".equals(listen)){
                            isAccessHttps = true;
                            String sslCertificate = ngxBlock.findParam("ssl_certificate").getValue();
                            String sslCertificateKey = ngxBlock.findParam("ssl_certificate_key").getValue();
                            //判断证书是否存在并不为空
                            if(FileUtil.exist(sslCertificate) && FileUtil.isNotEmpty(FileUtil.file(sslCertificate))){
                                havSslCert = true;
                            }
                            if(FileUtil.exist(sslCertificateKey) && FileUtil.isNotEmpty(FileUtil.file(sslCertificateKey))){
                                havSslCertKey = true;
                            }
                        }
                    }
                }
                obj.setIsAccessHttp(isAccessHttp);
                obj.setIsAccessHttps(isAccessHttps);
                obj.setIsAutoHttps(isAutoHttps);
                obj.setHavSslCert(havSslCert);
                obj.setHavSslCertKey(havSslCertKey);
            });
        }
        return R.ok(iPage);
    }

    /**
     * H5前端域名查询
     * @param id
     * @return R
     */
    @Operation(summary = "H5前端域名查询")
    @GetMapping("/{id}")
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:get')")
    public R getById(@PathVariable("id") String id) {
        return R.ok(h5PortalDomainService.getById(id));
    }

    /**
     * H5前端域名新增
     * @param h5PortalDomain H5前端域名
     * @return R
     */
    @Operation(summary = "H5前端域名新增")
    @SysLog("新增H5前端域名")
    @PostMapping
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:add')")
    public R save(@RequestBody H5PortalDomain h5PortalDomain) {
		h5PortalDomain.setTenantId(TenantContextHolder.getTenantId());
        h5PortalDomain.setIsDefault(CommonConstants.NO);
        return R.ok(h5PortalDomainService.save(h5PortalDomain));
    }

    /**
     * H5前端域名修改
     * @param h5PortalDomain H5前端域名
     * @return R
     */
    @Operation(summary = "H5前端域名修改")
    @SysLog("修改H5前端域名")
    @PutMapping
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:edit')")
    public R updateById(@RequestBody H5PortalDomain h5PortalDomain) {
		h5PortalDomain.setTenantId(TenantContextHolder.getTenantId());
        return R.ok(h5PortalDomainService.updateById(h5PortalDomain));
    }

    /**
     * H5前端域名删除
     * @param id
     * @return R
     */
    @Operation(summary = "H5前端域名删除")
    @SysLog("删除H5前端域名")
    @DeleteMapping("/{id}")
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:del')")
    public R removeById(@PathVariable String id) throws IOException {
        //先删除nginx配置
        H5PortalDomain h5PortalDomain = new H5PortalDomain();
        h5PortalDomain.setId(id);
        h5PortalDomain.setProtocol("http");
        this.delServer(h5PortalDomain);
        h5PortalDomain.setProtocol("https");
        this.delServer(h5PortalDomain);
        return R.ok(h5PortalDomainService.removeById(id));
    }

	/**
	 * H5前端域名查询
	 * @param id
	 * @return R
	 */
	@Operation(summary = "H5前端域名查询")
	@GetMapping("/inside/{id}")
	@Inside
	public R getByIdInside(@PathVariable("id") String id) {
		return R.ok(h5PortalDomainService.getById(id));
	}

	/**
	 * 生成默认域名
	 * @param h5PortalDomain
	 * @return R
	 */
	@Operation(summary = "生成默认域名")
	@SysLog("生成默认域名")
	@PostMapping("/default")
	@PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:index')")
	public R createDefault(@RequestBody H5PortalDomain h5PortalDomain) {
		h5PortalDomainService.createDefault(h5PortalDomain);
		return R.ok();
	}

    /**
     * 添加nginx Server配置
     * @return R
     */
    @Operation(summary = "添加nginx Server配置")
    @SysLog("添加nginx Server配置")
    @PostMapping("/nginx/server")
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:edit')")
    public R addServer(@RequestBody H5PortalDomain h5PortalDomain) throws IOException {
        if(StrUtil.isBlank(h5PortalDomain.getId())){
            return R.failed("id不能为空");
        }
        WebHost webHost = new WebHost();
        webHost.setHost(h5PortalDomain.getId());
        webHost.setProtocol(h5PortalDomain.getProtocol());
        webHost.setTenantId(TenantContextHolder.getTenantId());
        webHost.setHomeDir(homeDirConfigProperties.getHomeDir());
        webHost.setH5Path(h5portalPathProperties.getPath(h5PortalDomainService.getById(h5PortalDomain.getId()).getType()));
        return R.ok(NginxConfigUtil.addServer(webHost, nginxConfigProperties.getConfDir() + TenantContextHolder.getTenantId() + ".conf"));
    }

    /**
     * 删除nginx Server配置
     * @return R
     */
    @Operation(summary = "删除nginx Server配置")
    @SysLog("删除nginx Server配置")
    @DeleteMapping("/nginx/server")
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:edit')")
    public R delServer(@RequestBody H5PortalDomain h5PortalDomain) throws IOException {
        WebHost webHost = new WebHost();
        webHost.setHost(h5PortalDomain.getId());
        webHost.setProtocol(h5PortalDomain.getProtocol());
        return R.ok(NginxConfigUtil.delServer(webHost, nginxConfigProperties.getConfDir() + TenantContextHolder.getTenantId() + ".conf"));
    }

    /**
     * 开启http转https nginx Server配置
     * @param h5PortalDomain
     * @return
     * @throws IOException
     */
    @Operation(summary = "开启http转https nginx Server配置")
    @SysLog("开启http转https nginx Server配置")
    @PostMapping("/nginx/server/httptohttps/on")
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:edit')")
    public R httpTohttpsOn(@RequestBody H5PortalDomain h5PortalDomain) throws IOException {
        WebHost webHost = new WebHost();
        webHost.setHost(h5PortalDomain.getId());
        return R.ok(NginxConfigUtil.httpToHttps(webHost, nginxConfigProperties.getConfDir() + TenantContextHolder.getTenantId() + ".conf"));
    }

    /**
     * 关闭http转https nginx Server配置
     * @param h5PortalDomain
     * @return
     * @throws IOException
     */
    @Operation(summary = "关闭http转https nginx Server配置")
    @SysLog("关闭http转https nginx Server配置")
    @PostMapping("/nginx/server/httptohttps/off")
    @PreAuthorize("@ato.hasAuthority('sys:h5portaldomain:edit')")
    public R httpTohttpsOff(@RequestBody H5PortalDomain h5PortalDomain) throws IOException {
        if(StrUtil.isBlank(h5PortalDomain.getId())){
            return R.failed("id不能为空");
        }
        //先删除后新增
        WebHost webHost = new WebHost();
        webHost.setHost(h5PortalDomain.getId());
        webHost.setProtocol("http");
        NginxConfigUtil.delServer(webHost, nginxConfigProperties.getConfDir() + TenantContextHolder.getTenantId() + ".conf");
        webHost.setTenantId(TenantContextHolder.getTenantId());
        webHost.setHomeDir(homeDirConfigProperties.getHomeDir());
        webHost.setH5Path(h5portalPathProperties.getPath(h5PortalDomainService.getById(h5PortalDomain.getId()).getType()));
        NginxConfigUtil.addServer(webHost, nginxConfigProperties.getConfDir() + TenantContextHolder.getTenantId() + ".conf");
        return R.ok();
    }

    /**
     * 上传https证书
     * @param mulFile
     * @return
     */
    @Operation(summary = "上传https证书")
    @PostMapping("/ssl/upload")
    public String uploadFile(@RequestParam("file") MultipartFile mulFile, @RequestParam("id") String id) throws IOException {
        H5PortalDomain h5PortalDomain = h5PortalDomainService.getById(id);
        if(h5PortalDomain == null){
            return "无此域名";
        }
        File file = FileUtils.multipartFileToFile(mulFile);
        Map<Object, Object> responseData = new HashMap<>();
        String home = homeDirConfigProperties.getHomeDir();
        String dir = StrUtil.format("{}/{}/{}/{}/", home,"ssl", TenantContextHolder.getTenantId(), id);
        File file2 = FileUtil.writeBytes(FileUtil.readBytes(file), dir + id + "." + FileUtil.getSuffix(file));
        responseData.put("link", file2.getPath());
        return JSONUtil.toJsonStr(responseData);
    }
}
